﻿/*
 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved.
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */

// Register a plugin named "sample".
CKEDITOR.plugins.add('keystrokes',
    {
        beforeInit: function (editor) {
            /**
             * Controls keystrokes typing in this editor instance.
             * @name CKEDITOR.editor.prototype.keystrokeHandler
             * @type CKEDITOR.keystrokeHandler
             * @example
             */
            editor.keystrokeHandler = new CKEDITOR.keystrokeHandler(editor);

            editor.specialKeys = {};
        },

        init: function (editor) {
            var keystrokesConfig = editor.config.keystrokes,
                blockedConfig = editor.config.blockedKeystrokes;

            var keystrokes = editor.keystrokeHandler.keystrokes,
                blockedKeystrokes = editor.keystrokeHandler.blockedKeystrokes;

            for (var i = 0; i < keystrokesConfig.length; i++)
                keystrokes[keystrokesConfig[i][0]] = keystrokesConfig[i][1];

            for (i = 0; i < blockedConfig.length; i++)
                blockedKeystrokes[blockedConfig[i]] = 1;
        }
    });

/**
 * Controls keystrokes typing in an editor instance.
 * @constructor
 * @param {CKEDITOR.editor} editor The editor instance.
 * @example
 */
CKEDITOR.keystrokeHandler = function (editor) {
    if (editor.keystrokeHandler)
        return editor.keystrokeHandler;

    /**
     * List of keystrokes associated to commands. Each entry points to the
     * command to be executed.
     * @type Object
     * @example
     */
    this.keystrokes = {};

    /**
     * List of keystrokes that should be blocked if not defined at
     * {@link keystrokes}. In this way it is possible to block the default
     * browser behavior for those keystrokes.
     * @type Object
     * @example
     */
    this.blockedKeystrokes = {};

    this._ =
    {
        editor: editor
    };

    return this;
};

(function () {
    var cancel;

    var onKeyDown = function (event) {
        // The DOM event object is passed by the "data" property.
        event = event.data;

        var keyCombination = event.getKeystroke();
        var command = this.keystrokes[keyCombination];
        var editor = this._.editor;

        cancel = ( editor.fire('key', {keyCode: keyCombination}) === true );

        if (!cancel) {
            if (command) {
                var data = {from: 'keystrokeHandler'};
                cancel = ( editor.execCommand(command, data) !== false );
            }

            if (!cancel) {
                var handler = editor.specialKeys[keyCombination];
                cancel = ( handler && handler(editor) === true );

                if (!cancel)
                    cancel = !!this.blockedKeystrokes[keyCombination];
            }
        }

        if (cancel)
            event.preventDefault(true);

        return !cancel;
    };

    var onKeyPress = function (event) {
        if (cancel) {
            cancel = false;
            event.data.preventDefault(true);
        }
    };

    CKEDITOR.keystrokeHandler.prototype =
    {
        /**
         * Attaches this keystroke handle to a DOM object. Keystrokes typed
         ** over this object will get handled by this keystrokeHandler.
         * @param {CKEDITOR.dom.domObject} domObject The DOM object to attach
         *        to.
         * @example
         */
        attach: function (domObject) {
            // For most browsers, it is enough to listen to the keydown event
            // only.
            domObject.on('keydown', onKeyDown, this);

            // Some browsers instead, don't cancel key events in the keydown, but in the
            // keypress. So we must do a longer trip in those cases.
            if (CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ))
                domObject.on('keypress', onKeyPress, this);
        }
    };
})();

/**
 * A list of keystrokes to be blocked if not defined in the {@link CKEDITOR.config.keystrokes}
 * setting. In this way it is possible to block the default browser behavior
 * for those keystrokes.
 * @type Array
 * @default (see example)
 * @example
 * // This is actually the default value.
 * config.blockedKeystrokes =
 * [
 *     CKEDITOR.CTRL + 66 &#47;*B*&#47;,
 *     CKEDITOR.CTRL + 73 &#47;*I*&#47;,
 *     CKEDITOR.CTRL + 85 &#47;*U*&#47;
 * ];
 */
CKEDITOR.config.blockedKeystrokes =
    [
        CKEDITOR.CTRL + 66 /*B*/,
        CKEDITOR.CTRL + 73 /*I*/,
        CKEDITOR.CTRL + 85 /*U*/
    ];

/**
 * A list associating keystrokes to editor commands. Each element in the list
 * is an array where the first item is the keystroke, and the second is the
 * name of the command to be executed.
 * @type Array
 * @default (see example)
 * @example
 * // This is actually the default value.
 * config.keystrokes =
 * [
 *     [ CKEDITOR.ALT + 121 &#47;*F10*&#47;, 'toolbarFocus' ],
 *     [ CKEDITOR.ALT + 122 &#47;*F11*&#47;, 'elementsPathFocus' ],
 *
 *     [ CKEDITOR.SHIFT + 121 &#47;*F10*&#47;, 'contextMenu' ],
 *
 *     [ CKEDITOR.CTRL + 90 &#47;*Z*&#47;, 'undo' ],
 *     [ CKEDITOR.CTRL + 89 &#47;*Y*&#47;, 'redo' ],
 *     [ CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 &#47;*Z*&#47;, 'redo' ],
 *
 *     [ CKEDITOR.CTRL + 76 &#47;*L*&#47;, 'link' ],
 *
 *     [ CKEDITOR.CTRL + 66 &#47;*B*&#47;, 'bold' ],
 *     [ CKEDITOR.CTRL + 73 &#47;*I*&#47;, 'italic' ],
 *     [ CKEDITOR.CTRL + 85 &#47;*U*&#47;, 'underline' ],
 *
 *     [ CKEDITOR.ALT + 109 &#47;*-*&#47;, 'toolbarCollapse' ]
 * ];
 */
CKEDITOR.config.keystrokes =
    [
        [CKEDITOR.ALT + 121 /*F10*/, 'toolbarFocus'],
        [CKEDITOR.ALT + 122 /*F11*/, 'elementsPathFocus'],

        [CKEDITOR.SHIFT + 121 /*F10*/, 'contextMenu'],
        [CKEDITOR.CTRL + CKEDITOR.SHIFT + 121 /*F10*/, 'contextMenu'],

        [CKEDITOR.CTRL + 90 /*Z*/, 'undo'],
        [CKEDITOR.CTRL + 89 /*Y*/, 'redo'],
        [CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/, 'redo'],

        [CKEDITOR.CTRL + 76 /*L*/, 'link'],

        [CKEDITOR.CTRL + 66 /*B*/, 'bold'],
        [CKEDITOR.CTRL + 73 /*I*/, 'italic'],
        [CKEDITOR.CTRL + 85 /*U*/, 'underline'],

        [CKEDITOR.ALT + ( CKEDITOR.env.ie || CKEDITOR.env.webkit ? 189 : 109 ) /*-*/, 'toolbarCollapse'],
        [CKEDITOR.ALT + 48 /*0*/, 'a11yHelp']
    ];

/**
 * Fired when any keyboard key (or combination) is pressed into the editing area.
 * @name CKEDITOR.editor#key
 * @event
 * @param {Number} data.keyCode A number representing the key code (or
 *        combination). It is the sum of the current key code and the
 *        {@link CKEDITOR.CTRL}, {@link CKEDITOR.SHIFT} and {@link CKEDITOR.ALT}
 *        constants, if those are pressed.
 */
